package com.dp.mallchat.common.user.sensitive;

import cn.hutool.extra.tokenizer.Word;
import cn.hutool.json.JSONUtil;
import com.dp.mallchat.common.user.domain.entity.SensitiveWord;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @Author: dupeng
 * @CreateTime: 2024-07-22  17:01
 * @Description: DFA算法过滤
 */
public class DFAFilter implements SensitiveWordsFilter{

    private static Word root = new Word(' ');   //根节点
    private final static char replace = '*'; // 替代字符

    private final static String skipChars = " !*-+_=,，.@;:；：。、？?（）()【】[]《》<>“”\"‘’"; // 遇到这些字符就会跳过
    private final static Set<Character> skipSet = new HashSet<>(); // 遇到这些字符就会跳过

    static {
        for (char c : skipChars.toCharArray()) {
            skipSet.add(c);
        }
    }

    public static DFAFilter getInstance() {
        return new DFAFilter();
    }

    @Override
    public void loadSensitiveWords(List<String> wordList) {
        if (!CollectionUtils.isEmpty(wordList)) {
            wordList.forEach(word -> loadWord(word, root));
        }
    }

    /**
     * 加载敏感词
     * @param content 文本内容
     * @param root 根节点
     */
    private void loadWord(String content, Word root) {
        if (StringUtils.isBlank(content)) {
            return;
        }
        Word currentWord = root;
        for (int i = 0; i < content.length(); i++) {
            char c = content.charAt(i);
            // 跳过指定的字符
            if (skip(c)){
                continue;
            }
            //转小写
            if (c >= 'A' && c <= 'Z') {
                c += 32;
            }
            Word next = currentWord.next.get(c);
            if (null == next){
                next = new Word(c);
                currentWord.next.put(c, next);
            }
            currentWord = next;
        }
        currentWord.end = true;
    }

    /**
     * 需要跳过的字符
     * @param c 字符
     * @return 是否需要跳过
     */
    private boolean skip(char c) {
        return skipSet.contains(c);
    }

    @Override
    public boolean isSensitiveWords(String word) {
        if (StringUtils.isBlank(word)) return false;
        return !Objects.equals(word, filter(word));
    }

    @Override
    public String filter(String content) {
        StringBuilder result = new StringBuilder(content);
        int index = 0;
        while (index < result.length()) {
            char c = result.charAt(index);
            if (skip(c)) {
                index++;
                continue;
            }
            Word word = root;
            int start = index;  // 记录敏感词的起始位置
            boolean found = false;
            for (int i = index; i < result.length(); i++) {
                c = result.charAt(i);
                if (skip(c)) {
                    continue;
                }
                if (c >= 'A' && c <= 'Z') {
                    c += 32;
                }
                word = word.next.get(c);
                if (word == null) {
                    break;
                }
                if (word.end) { // 成功匹配到最后一个节点，进行敏感词替换
                    found = true;
                    for (int j = start; j <= i; j++) {
                        result.setCharAt(j, replace);
                    }
                    index = i;
                }
            }
            if (!found) {
                index++;
            }
        }
        return result.toString();
    }


    /**
     * 敏感词树
     */
    private static class Word{
        //当前字符
        private char c;
        //是否结束
        private boolean end;
        //下个节点
        private Map<Character, Word> next;

        public Word(char c){
            this.c = c;
            this.next = new HashMap<>();
        }
    }

    public static void main(String[] args) {
         DFAFilter dfaFilter = new DFAFilter();
        dfaFilter.loadSensitiveWords(Arrays.asList("敏感词","敏感词1","敏感词2"));
        System.out.println(dfaFilter.filter("是敏感 词哦"));
        System.out.println(JSONUtil.toJsonStr(root));
    }
}
